/* ------------------------------------------------------------------ Support code for problem set #5 SOURCE CODE ------------------------------------------------------------------- */ #include "support.hh" #include #include #include #include ifstream parameter_file("parameters"); void read_data(string filename, matrix& input, matrix& output) { ifstream data(filename); int patterns, inputs, outputs; data.scan("# patterns = %d", &patterns); data.scan("# inputs = %d", &inputs); data.scan("# outputs = %d", &outputs); input.resize(patterns, inputs); output.resize(patterns, outputs); for (int i = 0; i < patterns; i++) { for (int j = 0; j < inputs; j++) data >> input[i][j]; for (j = 0; j < outputs; j++) data >> output[i][j]; } } int seeded = 0; double random_number() { if (!seeded) { srandom(getpid()); seeded = 1; } return ((double) (random() % 100000)) / 50000.0 - 1.0; } char fscan_until(istream &is, string& str) { if (str.len() == 0 ) return 0; char lastc = 0, c; int i = 0; do { is.get(c); if (lastc == '\n' && c == '#') { i = 0; fscan_until(is, "\n"); lastc = '\n'; } else { if (c == str[i]) i++; else if (c == str[0]) i = 1; else i = 0; lastc = c; } } while (str[i] != '\0' && !is.eof()); return is.eof(); } void read_parameter(string& parameter_name, double& parameter, double default_value) { if (parameter_file.bad()) { cerr << "ERROR: Attempt to read nonexistent parameter file\n"; } parameter_file.seekg(0); fscan_until(parameter_file, parameter_name); parameter_file >> parameter; if (parameter_file.fail()) parameter = default_value; } void read_parameter(string& parameter_name, int& parameter, int default_value) { if (parameter_file.bad()) { cerr << "ERROR: Attempt to read nonexistent parameter file\n"; } parameter_file.seekg(0); fscan_until(parameter_file, parameter_name); parameter_file >> parameter; if (parameter_file.fail()) parameter = default_value; } vector augment(vector& v) return w(v); { w.upsize(v.dimension() + 1); w[v.dimension()] = 1; } class SVD_matrix { /* =================================================================== P U B L I C =================================================================== */ public: SVD_matrix(const matrix& m, double tol = 1E-12); friend SVD_matrix SVD(const matrix& m); friend SVD_matrix SVD(const matrix& m, double tol); vector solve(vector b) const; vector solve(vector b, vector& residual) const; matrix pseudoinverse(void) const; vector singular_values(void) { return w; } matrix range_basis(void) {return u; } matrix kernel_basis(void) { return v; } void set_tolerance(double new_tol) { tolerance = new_tol; } /* =================================================================== P R O T E C T E D =================================================================== */ protected: double tolerance; // zero for small singular values int n_rows; int n_cols; matrix u; // Columns of U give range basis vector w; // Singular values matrix v; // Columns of V give kernel basis double pythag(double a, double b); void SVD_decomp(const matrix& mat); }; inline SVD_matrix SVD(const matrix& m) return svd(m); { } inline SVD_matrix SVD(const matrix& m, double tol) return svd(m, tol); { } matrix pseudoinverse(matrix& M) { SVD_matrix svd(M); return svd.pseudoinverse(); } /******************************************************************/ /* Numerical Recipes Macros */ /******************************************************************/ inline float SQR(float a) { return (a == 0.0 ? 0.0 : a * a); } inline double SQR(double a) { return (a == 0.0 ? 0.0 : a * a); } inline double MAX(double a, double b) { return (a > b ? a : b); } inline double MIN(double a, double b) { return (a < b ? a : b); } inline float MAX(float a, float b) { return (a > b ? a : b); } inline float MIN(float a, float b) { return (a < b ? a : b); } inline int MAX(int a, int b) { return (a > b ? a : b); } inline int MIN(int a, int b) { return (a < b ? a : b); } inline long MAX(long a, long b) { return (a > b ? a : b); } inline long MIN(long a, long b) { return (a < b ? a : b); } inline double SIGN(double a, double b) { return (b >= 0.0 ? fabs(a) : -fabs(a)); } // return a square matrix whose diagonal elements are given by v matrix diag(const vector& v) return m(v.dimension(), v.dimension()); { for (register int i=0; i absb) return absa * sqrt(1.0 + SQR(absb/absa)); else return (absb == 0.0 ? 0.0 : absb * sqrt(1.0 + SQR(absa/absb))); } void SVD_matrix::SVD_decomp(const matrix& mat) { matrix a(mat); int m = n_rows; int n = n_cols; int flag,i,its,j,jj,k,l,nm; double anorm, c, f, g, h, s, scale, x, y, z; vector rv1(n); g=scale=anorm=0.0; // Begin Householder reduction to bidiagonal form for (i=0;i=0;i--) { if (i < n-1) { if (g) { for (j=l;j=0;i--) { l=i+1; g=w[i]; for (j=l;j=0;k--) { for (its=1;its<=30;its++) { // Allow 30 iterations flag=1; for (l=k;l>=0;l--) { // Test for splitting nm=l-1; // Note that rv1[0] is always 0.0 if ((double)(fabs(rv1[l])+anorm) == anorm) { flag=0; break; } if (nm < 0) cout << "WARNING: nm out of range for a vector\n"; if ((double)(fabs(w[nm])+anorm) == anorm) break; } if (flag) { c=0.0; // Cancellation of rv1[l], if l > 0 s=1.0; for (i=l;i<=k;i++) { f=s*rv1[i]; rv1[i]=c*rv1[i]; if ((double)(fabs(f)+anorm) == anorm) break; g=w[i]; h=pythag(f,g); w[i]=h; h=1.0/h; c=g*h; s = -f*h; for (j=0;j